package com.xb.loan.cashier.biz.job;

import com.xb.loan.cashier.biz.dao.bean.CashierEncashBatch;
import com.xb.loan.cashier.biz.dao.bean.CashierEncashOrder;
import com.xb.loan.cashier.biz.dao.bean.CashierPayChannelType;
import com.xb.loan.cashier.biz.dao.bean.CashierPlatPaytype;
import com.xb.loan.cashier.biz.service.CashierEncashBatchService;
import com.xb.loan.cashier.biz.service.CashierEncashOrderService;
import com.xb.loan.cashier.biz.service.CashierPayChannelBankService;
import com.xb.loan.cashier.biz.service.CashierPlatPaytypeService;
import com.xb.loan.cashier.service.constant.ICashierEnumConst;
import com.xb.loan.util.StringUtils;
import com.xb.loan.util.log.LogFormatTemplate;
import com.xb.loan.util.qrtz.task.AbstractCronTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 监控数据库，为数据库中状态为未处理的订单分配批次号和第三方提现渠道，处理完成一个批次后更新任务状态
 * 如果收银台需要部署多套，则在同一时间这个任务只能由其中一套执行
 *
 */
public class EncashFetchJob extends AbstractCronTask {
    
    private static Logger log = LoggerFactory.getLogger(EncashFetchJob.class);
	
	private CashierPayChannelBankService cashierPayChannelBankService;
    private CashierEncashOrderService cashierEncashOrderService;
	private CashierEncashBatchService cashierEncashBatchService;
    private CashierPlatPaytypeService cashierPlatPaytypeService;
	
	private static final int PAGE_SIZE = 500;                   // 分页大小
    private static final int DEFAULT_ENCASH_LIMIT = 500;        // 默认每个批次提现条数
	

	@Override
	public void run() {
	    execute();
	}
	
	public void execute(){
		log.info("提现分批JOB开始执行：EncashFetchJob");
	    if(cashierPayChannelBankService==null){
	        cashierPayChannelBankService = getSpringBean("cashierPayChannelBankService");
	    }
	    if(cashierEncashOrderService==null){
	        cashierEncashOrderService = getSpringBean("cashierEncashOrderService");
	    }
	    if(cashierEncashBatchService==null){
	        cashierEncashBatchService = getSpringBean("cashierEncashBatchService");
	    }
	    if(cashierPlatPaytypeService==null){
	        cashierPlatPaytypeService = getSpringBean("cashierPlatPaytypeService");
	    }
	    
        // 0.初始化未完成的提现记录
        fetchHistoryOrders();
        
//        // 2.初始化提现记录
//        fetchOrdersBatch(null);
        log.info("提现分批JOB执行结束：EncashFetchJob");
	}

	// 处理历史批次
    private void fetchHistoryOrders() {
        List<CashierEncashBatch> historyBatchs = cashierEncashBatchService.selectWaitBatchs();//查询待处理批次数据
        
        Map<String, Map<String, List<CashierEncashBatch>>> bankChannelBatchsMap = null;                // 银行、渠道ID、任务列表
        
        if(!CollectionUtils.isEmpty(historyBatchs)){
            bankChannelBatchsMap = new HashMap<String, Map<String, List<CashierEncashBatch>>>();
            String bankCode = null;
            String payChannelId = null;
            for(CashierEncashBatch batch : historyBatchs){
                try {
                    int batchCount = cashierEncashOrderService.selectBatchCount(batch.getBatchId());//查询同批次提现订单数量
                    if(batchCount<=0){
                        continue;
                    }
                    bankCode = batch.getBankCodePlat(); // 业务系统银行编码
                    payChannelId = batch.getPayChannelId();//支付渠道
                    batch.setCount(batchCount); // 批次的提现数量
                    Map<String, List<CashierEncashBatch>> channelBatchsMap = bankChannelBatchsMap.get(bankCode);
                    if(channelBatchsMap==null){
                        channelBatchsMap = new HashMap<String, List<CashierEncashBatch>>();
                        bankChannelBatchsMap.put(bankCode, channelBatchsMap);
                    }
                    List<CashierEncashBatch> batchs = channelBatchsMap.get(payChannelId);
                    if(batchs==null){
                        batchs = new ArrayList<CashierEncashBatch>();
                        channelBatchsMap.put(payChannelId, batchs);
                    }
                    batchs.add(batch);
                } catch (Exception e) {
                    log.error(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", null, null, null, batch.getBatchId(), "初始化历史批次数据失败！"}, e);
                }
            }
        }
        fetchOrdersBatch(bankChannelBatchsMap);
    }
    
    // 根据银行处理批次
    private void fetchOrdersBatch(Map<String, Map<String, List<CashierEncashBatch>>> historyBatchs){
        // 循环所有银行，更新数据库中未处理的提现订单，批次号为指定值、状态为处理中，处理每个批次第一条数据时添加任务，处理完成后更新任务状态
        List<String> bankCodes = cashierPayChannelBankService.getAllBankCodePlat();//distinct查询平台下所有bankCode
        if(CollectionUtils.isEmpty(bankCodes)){
        	log.warn("bankCodes为空，无法进行提现批次处理....");
            return ;
        }
        
        // 银行、渠道、任务列表
        Map<String, Map<String, List<CashierEncashBatch>>> batchs = new HashMap<String, Map<String, List<CashierEncashBatch>>>();
        if(!CollectionUtils.isEmpty(historyBatchs)){
            batchs.putAll(historyBatchs);
        }
        
        for(String bankCode : bankCodes){
            try {
                Map<String, List<CashierEncashBatch>> channelBatchsMap = batchs.get(bankCode);
                if(channelBatchsMap==null){
                    channelBatchsMap = new HashMap<String, List<CashierEncashBatch>>();
                    batchs.put(bankCode, channelBatchsMap);
                }
                fetchOrdersBatchBank(bankCode, channelBatchsMap);
            } catch (Exception e) {
                log.error(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", null, null, bankCode, null, "初始化银行数据失败！"}, e);
            }
        }
    }
    
    private void fetchOrdersBatchBank(String bankCode, Map<String, List<CashierEncashBatch>> channelBatchsMap){
        Date now = new Date();
        int pageNo = 1;
        while(true){
            List<CashierEncashOrder> orders = cashierEncashOrderService.selectEncashOrders(ICashierEnumConst.CashierEncashStatus.WAIT.getStatus(), bankCode, now, pageNo, PAGE_SIZE);
            pageNo++;
            if(CollectionUtils.isEmpty(orders)){
                if(channelBatchsMap!=null && channelBatchsMap.size()>0){
                    for(List<CashierEncashBatch> list : channelBatchsMap.values()){
                        cashierEncashBatchService.updateToWaiting(list);//下面订单处理完成后更新批次数量，状态status=1
                    }
                }
                break;
            }
            for(CashierEncashOrder order : orders){
                try {
                    updateOrder(order, bankCode, channelBatchsMap);//首次添加批次记录并更新提现订单状态(status=0->1)和批次号
                } catch (Exception e) {
                    log.error(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", order.getCashierOrderId(), null, bankCode, null, "初始化提现订单失败！"}, e);
                }
            }
        }
    }
    
    private void updateOrder(CashierEncashOrder order, String bankCode, Map<String, List<CashierEncashBatch>> channelBatchsMap){
        String cashierOrderId = order.getCashierOrderId();
        // 获取所有的银行对应的支付渠道类型
        List<CashierPayChannelType> channelTypeList = cashierEncashOrderService.selectChannel(order.getSellBank());
        if(channelTypeList==null || channelTypeList.size() < 1){ // 支付渠道方式不存在
            log.warn(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", cashierOrderId, null, bankCode, null, "不支持的银行类型！"});
            return;
        }
        String platId = order.getPlatId();
        // int paychannelType = channelType.getPaychannelType();
        CashierPlatPaytype platPaytype = cashierPlatPaytypeService.selectByPlatAndChannelType(platId, channelTypeList, ICashierEnumConst.CashierPayType.encash.getCode());
        if(platPaytype==null){
            log.warn(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", cashierOrderId, null, bankCode, null, "不支持的银行类型！"});
            return;
        }
        String payChannelId = platPaytype.getChannelId();
        if(StringUtils.isBlank(payChannelId)){
            log.warn(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", cashierOrderId, null, bankCode, null, "支付渠道不存在！"});
            return;
        }
        List<CashierEncashBatch> batchs = channelBatchsMap.get(payChannelId);
        if(CollectionUtils.isEmpty(batchs)){
            batchs = new ArrayList<CashierEncashBatch>();
            channelBatchsMap.put(payChannelId, batchs);
        }
        CashierEncashBatch lastBatch = batchs.size()>0?batchs.get(batchs.size()-1):null;
        CashierEncashBatch currentBatch = lastBatch;
        String batchId = currentBatch==null?null:currentBatch.getBatchId();
        int count = currentBatch==null?0:currentBatch.getCount();
        
        // 第一个批次 或 超过批次数量上限使用新的批次
        CashierPayChannelType channelType = new CashierPayChannelType();
        for (CashierPayChannelType cashierPayChannelType : channelTypeList) {
			if(cashierPayChannelType.getPaychannelType() == platPaytype.getPaychannelType()){
				channelType = cashierPayChannelType;
				break;
			}
		}
        int encashLimit = channelType.getEncashLimit();
        encashLimit = encashLimit<=0?DEFAULT_ENCASH_LIMIT:encashLimit;
        if(StringUtils.isBlank(batchId) || count >= encashLimit){
            batchId = cashierEncashBatchService.getBatchId();
            count = 0;
            currentBatch = new CashierEncashBatch();
            currentBatch.setBatchId(batchId);
            currentBatch.setBankCodePlat(bankCode);
            currentBatch.setPayChannelId(payChannelId);
            currentBatch.setCount(count);
            currentBatch.setPaychannelType(platPaytype.getPaychannelType());
            currentBatch.setStatus(ICashierEnumConst.CashierEncashBatchStatus.WAIT.getStatus());
            batchs.add(currentBatch);
        }
        
        int row = 0;
        if(count==0){
            row = cashierEncashOrderService.initFirstEncashOrder(cashierOrderId, payChannelId, platPaytype.getPaychannelType(), bankCode, batchId);
        }else{
            row = cashierEncashOrderService.initEncashOrder(cashierOrderId, platPaytype.getPaychannelType(), batchId);
        }
        if(row < 1){
            log.warn(LogFormatTemplate.CASHIER_ENCASH_MODEL, new Object[]{"cashier", cashierOrderId, platPaytype.getPaychannelType(), bankCode, batchId, "更新提现订单批次号失败！"});
            return;
        }
        currentBatch.setCount(count+1);
    }

    public void setCashierPayChannelBankService(CashierPayChannelBankService cashierPayChannelBankService) {
        this.cashierPayChannelBankService = cashierPayChannelBankService;
    }

    public void setCashierEncashOrderService(CashierEncashOrderService cashierEncashOrderService) {
        this.cashierEncashOrderService = cashierEncashOrderService;
    }

    public void setCashierEncashBatchService(CashierEncashBatchService cashierEncashBatchService) {
        this.cashierEncashBatchService = cashierEncashBatchService;
    }

    public void setCashierPlatPaytypeService(CashierPlatPaytypeService cashierPlatPaytypeService) {
        this.cashierPlatPaytypeService = cashierPlatPaytypeService;
    }
    
}
